home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Hand Picked Software
/
Hand Picked Software.iso
/
aids
/
ar110
/
encode.bak
< prev
next >
Wrap
Text File
|
1995-03-13
|
6KB
|
236 lines
/***********************************************************
encode.c -- sliding dictionary with percolating update
***********************************************************/
#include "ar.h"
#include <stdlib.h>
#include <string.h> /* memmove() */
#define PERCOLATE 1
#define NIL 0
#define MAX_HASH_VAL (3 * DICSIZ + (DICSIZ / 512 + 1) * UCHAR_MAX)
typedef short node;
static uchar *text, *childcount;
static node pos, matchpos, avail,
*position, *parent, *prev, *next = NULL;
static int remainder, matchlen;
#if MAXMATCH <= (UCHAR_MAX + 1)
static uchar *level;
#else
static ushort *level;
#endif
static void allocate_memory(void)
{
if (next != NULL) return;
text = malloc(DICSIZ * 2 + MAXMATCH);
level = malloc((DICSIZ + UCHAR_MAX + 1) * sizeof(*level));
childcount = malloc((DICSIZ + UCHAR_MAX + 1) * sizeof(*childcount));
#if PERCOLATE
position = malloc((DICSIZ + UCHAR_MAX + 1) * sizeof(*position));
#else
position = malloc(DICSIZ * sizeof(*position));
#endif
parent = malloc(DICSIZ * 2 * sizeof(*parent));
prev = malloc(DICSIZ * 2 * sizeof(*prev));
next = malloc((MAX_HASH_VAL + 1) * sizeof(*next));
if (next == NULL) error("Out of memory.");
}
static void init_slide(void)
{
node i;
for (i = DICSIZ; i <= DICSIZ + UCHAR_MAX; i++) {
level[i] = 1;
#if PERCOLATE
position[i] = NIL; /* sentinel */
#endif
}
for (i = DICSIZ; i < DICSIZ * 2; i++) parent[i] = NIL;
avail = 1;
for (i = 1; i < DICSIZ - 1; i++) next[i] = i + 1;
next[DICSIZ - 1] = NIL;
for (i = DICSIZ * 2; i <= MAX_HASH_VAL; i++) next[i] = NIL;
}
#define HASH(p, c) ((p) + ((c) << (DICBIT - 9)) + DICSIZ * 2)
static node child(node q, uchar c)
/* q's child for character c (NIL if not found) */
{
node r;
r = next[HASH(q, c)];
parent[NIL] = q; /* sentinel */
while (parent[r] != q) r = next[r];
return r;
}
static void makechild(node q, uchar c, node r)
/* Let r be q's child for character c. */
{
node h, t;
h = HASH(q, c);
t = next[h]; next[h] = r; next[r] = t;
prev[t] = r; prev[r] = h;
parent[r] = q; childcount[q]++;
}
void split(node old)
{
node new, t;
new = avail; avail = next[new]; childcount[new] = 0;
t = prev[old]; prev[new] = t; next[t] = new;
t = next[old]; next[new] = t; prev[t] = new;
parent[new] = parent[old];
level[new] = matchlen;
position[new] = pos;
makechild(new, text[matchpos + matchlen], old);
makechild(new, text[pos + matchlen], pos);
}
static void insert_node(void)
{
node q, r, j, t;
uchar c, *t1, *t2;
if (matchlen >= 4) {
matchlen--;
r = (matchpos + 1) | DICSIZ;
while ((q = parent[r]) == NIL) r = next[r];
while (level[q] >= matchlen) {
r = q; q = parent[q];
}
#if PERCOLATE
t = q;
while (position[t] < 0) {
position[t] = pos; t = parent[t];
}
if (t < DICSIZ) position[t] = pos | PERC_FLAG;
#else
t = q;
while (t < DICSIZ) {
position[t] = pos; t = parent[t];
}
#endif
} else {
q = text[pos] + DICSIZ; c = text[pos + 1];
if ((r = child(q, c)) == NIL) {
makechild(q, c, pos); matchlen = 1;
return;
}
matchlen = 2;
}
for ( ; ; ) {
if (r >= DICSIZ) {
j = MAXMATCH; matchpos = r;
} else {
j = level[r];
matchpos = position[r] & ~PERC_FLAG;
}
if (matchpos >= pos) matchpos -= DICSIZ;
t1 = &text[pos + matchlen]; t2 = &text[matchpos + matchlen];
while (matchlen < j) {
if (*t1 != *t2) { split(r); return; }
matchlen++; t1++; t2++;
}
if (matchlen >= MAXMATCH) break;
position[r] = pos;
q = r;
if ((r = child(q, *t1)) == NIL) {
makechild(q, *t1, pos); return;
}
matchlen++;
}
t = prev[r]; prev[pos] = t; next[t] = pos;
t = next[r]; next[pos] = t; prev[t] = pos;
parent[pos] = q; parent[r] = NIL;
next[r] = pos; /* special use of next[] */
}
static void delete_node(void)
{
#if PERCOLATE
node q, r, s, t, u;
#else
node r, s, t, u;
#endif
if (parent[pos] == NIL) return;
r = prev[pos]; s = next[pos];
next[r] = s; prev[s] = r;
r = parent[pos]; parent[pos] = NIL;
if (r >= DICSIZ || --childcount[r] > 1) return;
#if PERCOLATE
t = position[r] & ~PERC_FLAG;
#else
t = position[r];
#endif
if (t >= pos) t -= DICSIZ;
#if PERCOLATE
s = t; q = parent[r];
while ((u = position[q]) & PERC_FLAG) {
u &= ~PERC_FLAG; if (u >= pos) u -= DICSIZ;
if (u > s) s = u;
position[q] = (s | DICSIZ); q = parent[q];
}
if (q < DICSIZ) {
if (u >= pos) u -= DICSIZ;
if (u > s) s = u;
position[q] = s | DICSIZ | PERC_FLAG;
}
#endif
s = child(r, text[t + level[r]]);
t = prev[s]; u = next[s];
next[t] = u; prev[u] = t;
t = prev[r]; next[t] = s; prev[s] = t;
t = next[r]; prev[t] = s; next[s] = t;
parent[s] = parent[r]; parent[r] = NIL;
next[r] = avail; avail = r;
}
static void get_next_match(void)
{
int n;
remainder--;
if (++pos == DICSIZ * 2) {
memmove(&text[0], &text[DICSIZ], DICSIZ + MAXMATCH);
n = fread_crc(&text[DICSIZ + MAXMATCH], DICSIZ, infile);
remainder += n; pos = DICSIZ; putc('.', stderr);
}
delete_node(); insert_node();
}
void encode(void)
{
int lastmatchlen;
node lastmatchpos;
allocate_memory(); init_slide(); huf_encode_start();
remainder = fread_crc(&text[DICSIZ], DICSIZ + MAXMATCH, infile);
putc('.', stderr);
matchlen = 0;
pos = DICSIZ; insert_node();
if (matchlen > remainder) matchlen = remainder;
while (remainder > 0 && ! unpackable) {
lastmatchlen = matchlen; lastmatchpos = matchpos;
get_next_match();
if (matchlen > remainder) matchlen = remainder;
if (matchlen > lastmatchlen || lastmatchlen < THRESHOLD)
output(text[pos - 1], 0);
else {
output(lastmatchlen + (UCHAR_MAX + 1 - THRESHOLD),
(pos - lastmatchpos - 2) & (DICSIZ - 1));
while (--lastmatchlen > 0) get_next_match();
if (matchlen > remainder) matchlen = remainder;
}
}
huf_encode_end();
}